Skip to content

Comments

chore: migrate to React Router v6#1573

Merged
VikaCep merged 5 commits intomainfrom
chore/migrate-react-router-v6
Feb 13, 2026
Merged

chore: migrate to React Router v6#1573
VikaCep merged 5 commits intomainfrom
chore/migrate-react-router-v6

Conversation

@VikaCep
Copy link
Contributor

@VikaCep VikaCep commented Jan 30, 2026

Migrate to React Router v6

Closes #713

Problem

The application was using react-router-dom-v5-compat as a bridge between React Router v5 and v6. This compatibility layer:

  • Added unnecessary bundle size overhead
  • Required maintaining two different routing patterns in the codebase
  • Is deprecated and will be removed in future Grafana versions

Additionally, the test infrastructure relied on React Router v5 APIs through @grafana/ui components (Link, TextLink) and @grafana/runtime's locationService, which caused test failures after migrating to v6.

Solution

This PR completes the migration to React Router v6 by:

Runtime changes:

  • Upgraded react-router-dom from v5-compat to v6.27.0
  • Removed react-router-dom-v5-compat dependency entirely
  • Updated all navigation to use v6 APIs (useNavigate, useParams, useLocation)
  • Updated programmatic navigation to use locationService from @grafana/runtime
    ==> locationService.push()/replace() is preferred as it's a Grafana's abstraction, integrates with Grafana's location tracking/observability. useNavigate(), React Router's native hook, works but bypasses Grafana's layer

Test infrastructure updates:

  • Refactored test/render.tsx to use Router with locationService.getHistory() so both React Router and locationService share the same history instance
  • Updated @grafana/runtime mock for locationService implementation including history.block() support required by ConfirmLeavingPage
  • Updated @grafana/ui mock for Link and TextLink components to work without React Router v5 context (these components internally depend on v5)

Dependencies:

  • React upgraded to 18.3.0
  • Grafana packages upgraded to 12.2.0
  • Updated @grafana/create-plugin to v6.7.8
  • Enabled useReactRouterV6 feature flag

Notes

The test mocks for @grafana/ui components (Link, TextLink) are necessary because these components internally use React Router v5 APIs. Once Grafana updates @grafana/ui to support v6 natively these mocks should be simplified or removed.

@VikaCep VikaCep self-assigned this Jan 30, 2026
@github-actions github-actions bot added the chore A miscellaneous change added to the application. label Jan 30, 2026
@VikaCep VikaCep changed the title chore: migrate to React Router v6 chore: migrate to React Router v6 // WIP Jan 30, 2026
@VikaCep VikaCep force-pushed the feat/migrate-home-dashboard-to-react-scenes branch from 7c486ae to 1adf9b7 Compare February 3, 2026 14:51
Base automatically changed from feat/migrate-home-dashboard-to-react-scenes to main February 3, 2026 15:44
@VikaCep VikaCep force-pushed the chore/migrate-react-router-v6 branch from 1b43fb1 to 16502c3 Compare February 3, 2026 21:20
@github-actions
Copy link

github-actions bot commented Feb 3, 2026

Script size changes

Name +/- Main This PR Outcome
[217.js] New file - 2,190.04 kB
[361.js] New file - 801.47 kB
[datasource/module.js] +0.27% 25.18 kB 25.25 kB
[692.js] = 20.64 kB 20.64 kB
[663.js] = 5.83 kB 5.83 kB
[module.js] +1.26% 4.54 kB 4.59 kB
[156.js] = 1.90 kB 1.90 kB
[411.js] Deleted file 2,178.85 kB -
[854.js] Deleted file 801.09 kB -

Totals

Name +/- Main This PR Outcome
[Scripts] +0.39% 3,038.02 kB 3,049.72 kB
[Non-script Assets] = 2,677.50 kB 2,677.50 kB
[All] +0.20% 5,715.52 kB 5,727.22 kB

Generated by 🚫 dangerJS against fc72497

@VikaCep VikaCep force-pushed the chore/migrate-react-router-v6 branch 4 times, most recently from e236f39 to 39f0df9 Compare February 5, 2026 14:04
- Upgrade react-router-dom from v5 to v6.27.0
- Remove react-router-dom-v5-compat dependency
- Update React to 18.3.0 and Grafana packages to 12.2.0
- Migrate route imports and navigation to v6 APIs
- Use locationService for programmatic navigation
- Update webpack externals configuration
@VikaCep VikaCep force-pushed the chore/migrate-react-router-v6 branch from 39f0df9 to 6ddf83b Compare February 5, 2026 14:57
Initialize @grafana/i18n before rendering scenes components.
Workaround for grafana/scenes#1322
@VikaCep VikaCep force-pushed the chore/migrate-react-router-v6 branch from 6ddf83b to 0b40406 Compare February 5, 2026 15:08
@VikaCep VikaCep changed the title chore: migrate to React Router v6 // WIP chore: migrate to React Router v6 Feb 5, 2026
@VikaCep VikaCep marked this pull request as ready for review February 5, 2026 15:17
@VikaCep VikaCep requested review from a team as code owners February 5, 2026 15:17
@VikaCep VikaCep requested review from ckbedwell and g3john and removed request for a team February 5, 2026 15:17
g3john
g3john previously approved these changes Feb 11, 2026
Copy link
Contributor

@g3john g3john left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

ckbedwell
ckbedwell previously approved these changes Feb 13, 2026
Copy link
Contributor

@ckbedwell ckbedwell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One super teeny tiny nit.

This is great and glad we've removed this tech debt -- one thing that I couldn't work out as I was reviewing this PR: when should we use hooks from react-router directly vs locationService -- I even noticed there is a hook in the runtime package called useLocationService.

Does it make sense to migrate everything to using the location service abstraction at some point in the future so we are removed from the implementation detail of react-router or is it encouraged for us to use its hooks and methods directly?

I read through the documentation and couldn't find an answer and spot-checking other plugins I think they are as equally split as we are...

@VikaCep
Copy link
Contributor Author

VikaCep commented Feb 13, 2026

@ckbedwell Good question, locationService seems to be a wrapper around the history package. It handles programmatic navigation (push, replace, partial) and reading the current location, but it has no concept of route params, route matching, path generation, or nested routing. Those are purely React Router's domain.
So the way I see it:

  • locationService for programmatic navigation as it's Grafana's way to write to history
  • React Router hooks for reading route state (useParams, useSearchParams, useLocation) as there is no locationService equivalents.
  • React Router components for route declarations (Route, Routes, Navigate), no Grafana abstraction for these either

They're complementary. locationService wraps history, React Router consumes that same history.

@VikaCep VikaCep merged commit 6edc28b into main Feb 13, 2026
36 checks passed
@VikaCep VikaCep deleted the chore/migrate-react-router-v6 branch February 13, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore A miscellaneous change added to the application.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App plugin: Update to react-router v6

3 participants